package controller.mall;

import com.alibaba.druid.util.StringUtils;
import com.google.gson.*;
import model.InnerResult;
import model.Result;
import model.po.User;
import service.MallUserService;
import service.impl.MallUserServiceImpl;
import utils.HttpUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.time.format.DateTimeFormatter;
import java.util.function.Function;

import static model.InnerResult.Status.FULFILLED;

@WebServlet("/api/mall/user/*")
public class UserServlet extends HttpServlet {
    private MallUserService mallUserService = new MallUserServiceImpl();

    private final String URI_PREFIX = "/api/mall/user/";
    private final Gson GSON = new GsonBuilder().registerTypeAdapter(Timestamp.class, new TimestampSerializer()).create();

    private static class TimestampSerializer implements JsonSerializer<Timestamp> {
        final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        @Override
        public JsonElement serialize(Timestamp timestamp, Type type, JsonSerializationContext jsonSerializationContext) {
            return new JsonPrimitive(timestamp.toLocalDateTime().format(dtf));
        }
    }

    private final Function<InnerResult, Result> FILLER = dto -> {
        if (dto.getStatus() == FULFILLED) {
            return Result.fulfill(dto.getObject());
        } else {
            return Result.reject(dto.getObject().toString());
        }
    };

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getRequestURI().replace(URI_PREFIX, "");
        try {
            switch (action) {
                case "signup":
                    signup(req, resp);
                    break;
                case "login":
                    login(req, resp);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void login(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String requestBody = HttpUtils.getRequestBody(req);
        User user = GSON.fromJson(requestBody, User.class);
        if (StringUtils.isEmpty(user.getEmail()) || !user.getEmail().matches("^\\d{5,12}@[qQ][qQ]\\.(com|cn)$")) {
            resp.getWriter().print(GSON.toJson(Result.reject("非法参数")));
            return;
        }
        InnerResult result = mallUserService.login(user);
        resp.getWriter().print(GSON.toJson(FILLER.apply(result)));
    }

    private void signup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String requestBody = HttpUtils.getRequestBody(req);
        User user = GSON.fromJson(requestBody, User.class);
        if (isInvalid(user)) {
            resp.getWriter().print(GSON.toJson(Result.reject("非法参数")));
            return;
        }
        InnerResult result = mallUserService.signup(user);
        resp.getWriter().print(GSON.toJson(FILLER.apply(result)));
    }

    private boolean isInvalid(User user) {
        if (!user.getEmail().matches("^\\d{5,12}@[qQ][qQ]\\.(com|cn)$")) {
            return true;
        }

        if (!user.getNickname().matches("^[A-Za-z0-9]{4,15}$")) {
            return true;
        }

        if (!user.getPwd().matches("^.*(?=.{8,16})(?=.*\\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$")) {
            return true;
        }

        if (!user.getRecipient().matches("[\u4E00-\u9FA5]+")) {
            return true;
        }

        if (!user.getAddress().matches("[\u4E00-\u9FA5]+")) {
            return true;
        }

        if (!user.getPhone().matches("^1[3|4|5|8|7][0-9]\\d{4,8}$")) {
            return true;
        }
        return false;
    }
}
